package network.server;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.List;

import network.Client;
import network.Message;
import network.MessageFactory;
import controller.Constants;

/**
 * A whiteboard server is user to accept user connection request and handle it
 * by thread.
 * 
 * @author Jie Zhao(288654)
 * 
 */
public class WhiteboardServer implements Runnable {
	ServerSocket serverSocket = null;

	public WhiteboardServer() {
	}

	public WhiteboardServer(int port) {
		this.setPort(port);
	}

	private boolean isRunning = false;
	private int serverPort = 0;
	private String password = "";

	public void setPort(int port) {
		serverPort = port;
	}

	public void setPassword(String pwd) {
		this.password = pwd;
	}

	@Override
	public void run() {
		while (isRunning) {
			if (Constants.DEBUG)
				System.out.println("Server Started, waiting for connection...");
			try {
				Socket client = serverSocket.accept();
				ClientProcesser processer = new ClientProcesser(this, client);
				new Thread(processer).start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	public void start() throws Exception {
		serverSocket = new ServerSocket(serverPort);
		isRunning = true;
		Thread checker = new Thread(new Checker());
		checker.setDaemon(true);
		checker.start();
		new Thread(this).start();
	}

	public void stop() {
		isRunning = false;
	}

	public void close() {
		isRunning = false;
		stop();
	}

	public static void main(String[] args) {
		new Thread(new WhiteboardServer(1234)).start();
	}

	public String getPassword() {
		return password;
	}
}

/**
 * A checker is a daemon thread which is used to check if a client is still
 * alive.
 * 
 * @author Jie Zhao(288654)
 * 
 */
class Checker implements Runnable {
	private int checkInterval = 5;

	public void setCheckInterval(int second) {
		checkInterval = second;
	}

	@Override
	public void run() {
		if (Constants.DEBUG)
			System.out
					.println("Daemon Thread Starting... check client connection");
		Message m = MessageFactory.createCheckMessage();
		while (true) {
			try {
				List<Client> cl = ClientList.getInstance().getClientList();
				synchronized (cl) {

					for (Iterator<Client> i = cl.iterator(); i.hasNext();) {
						Client c = i.next();
						Socket s = c.getClientSocket();
						if (s == null)
							continue;
						if (s.isClosed() || !s.isConnected()) {
							if (Constants.DEBUG)
								System.out
										.println("Server Detect Client is closed:"
												+ s);
							i.remove();
							ClientList.getInstance().update();
						} else {
							try {
								s.getOutputStream().write(m.toByteArray());
							} catch (Exception e) {
								if (Constants.DEBUG)
									System.out
											.println("Server Detect Client is closed(From exception):"
													+ s);
								try {
									s.close();
								} catch (Exception ee) {
								}
								i.remove();
								ClientList.getInstance().update();
							}
						}
					}
				}
				Thread.sleep(checkInterval * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
}